﻿using CWCS.Common;
using CWCS.Entity;
using CWCS.Entity.Robot;
using HslCommunication;
using HslCommunication.Profinet.Siemens;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace CWCS.Core.Library.PLCManager
{
    public class RobotPLC : PLCHelper
    {
        string local_ip;
        // public Dictionary<string, OPCServer> PLCList = new Dictionary<string, OPCServer>();//PLC列表
        protected static Dictionary<string, SiemensS7Net> PLCList = new Dictionary<string, SiemensS7Net>();//PLC列表
        public static Dictionary<string, string> robotStatus = new Dictionary<string, string>();//机械手状态列表
        public List<RobotInfo> RobotsInfo = new List<RobotInfo>();
        private Dictionary<string, string> dicIP = new Dictionary<string, string>();

        private delegate void ReadOPCInfos(RobotInfo rbinfo);
        private event ReadOPCInfos ReadRobotOPCInfo;

        private delegate void ReConnetPLC(string ip, int retryCount);
        private event ReConnetPLC RobotReConnectPLC;
        public RobotPLC()
        {
            this.ReadRobotOPCInfo += new ReadOPCInfos(ReadRobotInfo);
            this.RobotReConnectPLC += new ReConnetPLC(ReConnect);
        }
        /// <summary>
        /// 初始化机械手
        /// </summary>
        /// <param name="lst"></param>
        /// <param name="error"></param>
        /// 
        public void InitData(List<RobotInfo> lst, ref string error)
        {
            try
            {
                foreach (var item in lst as List<RobotInfo>)
                {
                    local_ip = item.key_ip;
                    if (!PLCList.ContainsKey(local_ip))
                    {
                        SiemensS7Net siemens = new SiemensS7Net(SiemensPLCS.S1500)
                        {
                            IpAddress = local_ip,
                            Port = 102,
                            Slot = 1,
                            ConnectTimeOut = 1000
                        };
                        PLCList.Add(local_ip, siemens);
                        //长链接
                        OperateResult operateResult = PLCList[local_ip].ConnectServer();
                    }
                    if (!dicIP.ContainsKey(local_ip + ":" + item.robotnum))
                    {
                        dicIP.Add(local_ip + ":" + item.robotnum, item.robotnum);
                    }

                    RobotInit(item);
                }
            }
            catch (Exception ex)
            {
                error = ex.Message;
                ShowMsg("Init", "机械手初始化异常：" + ex.Message);
            }
        }
        private void RobotInit(RobotInfo rb)
        {
            if (!RobotsInfo.Contains(rb))
                RobotsInfo.Add(rb);
        }
        public void Run(object i_Index)
        {
            Thread threadCom = new Thread(new ParameterizedThreadStart(TimeScan));
            threadCom.IsBackground = true;
            threadCom.Start(i_Index);
        }
        private void TimeScan(object belong)
        {
            while (true)
            {
                try
                {
                    var lst = RobotsInfo.Where(it => it.belong == belong.ToString()).ToList();
                    if (lst.Count > 0)
                    {
                        foreach (RobotInfo rb in lst)
                        {
                            ReadRobotInfo(rb);
                        }
                    }
                }
                catch (Exception ex)
                {
                }
                Thread.Sleep(300);
            }
        }
        private void ReadRobotInfo(RobotInfo rb)
        {
            try
            {
                if (!robotStatus.ContainsKey(rb.name))
                {
                    robotStatus.Add(rb.name, "3");
                }
                if (rb.robotnum == "6003"|| rb.robotnum == "6004")
                { 
                
                }
                if (ReadRobotOPCInfo != null)
                {
                    Byte[] rbBuffer = new byte[rb.length];
                    if (ReadPlc(PLCList[rb.key_ip], rb.DBAddress, rb.start, rb.length, ref rbBuffer))
                    {
                        rb.m_ConnectStatus = true;

                        if (rb.stationtype == 1 || rb.stationtype == 5)//扫码校验
                        {
                            BindCheckRoboInfo(rb.robotnum, rbBuffer);
                        }
                        if (rb.stationtype == 2 || rb.stationtype == 4) //组盘
                        {
                            BindPutRoboInfo(rb.robotnum, rbBuffer);
                        }
                        if (rb.stationtype == 3)//拆盘
                        {
                            BindPickRoboInfo(rb.robotnum, rbBuffer);
                        }
                        #region 心跳值写入
                        if ((rb.stationtype == 2 || rb.stationtype == 3 || rb.stationtype == 4) && rb.heart == 1)
                        {
                            Write(rb.robotnum, "2", 10, 2);
                        }
                        #endregion
                    }
                    else
                    {
                        rb.m_ConnectStatus = false;
                        if (robotStatus.ContainsKey(rb.name))
                        {
                            robotStatus[rb.name] = "3";
                        }
                        ReConnect(rb.key_ip, 1);
                    }
                    ShowUI(rb);
                }
            }
            catch (Exception ex) { ShowMsg("Init", "机械手信息读取异常：" + ex.Message); }
        }
        public override string[] ReadPLCInfo(string EquipNum, int index = 0)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 清理电池信息或者托盘条码尾巴
        /// </summary>
        /// <param name="barcode"></param>
        private string clearbarcodeInfo(string barcode)
        {
            char[] c = new char[5];
            c[0] = '\0';
            c[1] = '\r';
            c[2] = '\n';
            c[3] = ' ';
            c[4] = ' ';
            barcode = barcode.Replace(c[0], c[4]).Replace("\r", "").Replace("\n", "").Replace(" ", "").Replace("", "").Trim(' ');
            return barcode;
        }

        private void BindCheckRoboInfo(string robotnum, byte[] byt)//校验请求
        {
            RobotInfo rb = RobotsInfo.Find(
                delegate(RobotInfo ss)
                {
                    return ss.robotnum == robotnum;
                }
            );
            if (rb != null)
            {
                byte[] BatteryCode1Tmp = new byte[rb.length];
                byte[] BatteryCode2Tmp = new byte[rb.length];
                byte[] BatteryCode3Tmp = new byte[rb.length];
                byte[] BatteryCode4Tmp = new byte[rb.length];
                //byte[] BatteryCode5Tmp = new byte[rb.length];
                //byte[] BatteryCode6Tmp = new byte[rb.length];
                rb.wcstaskno = (byt[0] * 256 + byt[1]).ToString();  //WCS任务号
                rb.rbtaskno = byt[2] * 256 + byt[3];//机器人运行状态 
                rb.rbstate = byt[4] * 256 + byt[5];//机器人运行状态 
                rb.workstation = byt[6] * 256 + byt[7];//装盘工位
                if (rb.stationtype == 1)
                {
                    rb.inplacebarcodereading = byt[8] * 256 + byt[9];//机器人条码到位               
                }
                else if (rb.stationtype == 5)
                {
                    rb.checkbarcodereading = byt[8] * 256 + byt[9];//机器人校验条码交互信号   
                }
                rb.barcode1ng = byt[12] * 256 + byt[13];
                rb.barcode2ng = byt[14] * 256 + byt[15];
                rb.barcode3ng = byt[16] * 256 + byt[17];
                rb.barcode4ng = byt[18] * 256 + byt[19];
                Array.Copy(byt, 22, BatteryCode1Tmp, 0, 30);
                Array.Copy(byt, 52, BatteryCode2Tmp, 0, 30);
                Array.Copy(byt, 82, BatteryCode3Tmp, 0, 30);
                Array.Copy(byt, 112, BatteryCode4Tmp, 0, 30);

                rb.barcode1 = clearbarcodeInfo(System.Text.Encoding.ASCII.GetString(BatteryCode1Tmp));
                rb.barcode2 = clearbarcodeInfo(System.Text.Encoding.ASCII.GetString(BatteryCode2Tmp));
                rb.barcode3 = clearbarcodeInfo(System.Text.Encoding.ASCII.GetString(BatteryCode3Tmp));
                rb.barcode4 = clearbarcodeInfo(System.Text.Encoding.ASCII.GetString(BatteryCode4Tmp));

                if (rb.checkbarcodereading > 0 || rb.inplacebarcodereading>0)
                {
                    //业务逻辑处理
                    ShowEquipmentTaskInfo(rb);
                }
            }
        }

        private void BindPutRoboInfo(string robotnum, byte[] byt)
        {
            RobotInfo rb = RobotsInfo.Find(
                delegate (RobotInfo ss)
                {
                    return ss.robotnum == robotnum;
                }
            );
            if (rb != null)
            {
                byte[] BatteryCode1Tmp = new byte[30];
                byte[] BatteryCode2Tmp = new byte[30];
                byte[] BatteryCode3Tmp = new byte[30];
                byte[] BatteryCode4Tmp = new byte[30];

                rb.wcstaskno = (byt[0] * 256 + byt[1]).ToString();//WCS任务号
                rb.rbtaskno = byt[2] * 256 + byt[3];//机器人任务号 0，无任务；1，装盘中；2，装盘完成(RB清0)
                rb.rbstate = byt[4] * 256 + byt[5];//机器人运行状态  0，未启动；1，自动；2，手动；3，故障
                rb.rbnumber = byt[6] * 256 + byt[7];//当前装盘数量
                rb.pickbarcodereading = byt[8] * 256 + byt[9];//机器人装盘条码读取信号 0，无指令；1，读取条码(RB)；2,读取完成(WCS);3,读到2后置0(RB)
                rb.heart= byt[10] * 256 + byt[11];//心跳
                rb.alarmCode = byt[12] * 256 + byt[13];//故障代码
                robotStatus[rb.name] = rb.rbstate.ToString();
                //获取rb.cellNum个电芯条码，放入BarCodeList
                rb.BarCodeList.Clear();
                for (int i = 0; i < rb.cellNum; i++)
                {
                    byte[] BatteryCodeTmp = new byte[30];
                    string barCode = string.Empty;
                    Array.Copy(byt, 68 + 30 * i, BatteryCodeTmp, 0, 30);
                    barCode = Encoding.ASCII.GetString(BatteryCodeTmp).Replace(" ", "").Trim('\0').Trim('\r').Trim('\n').Trim('\t');
                    rb.BarCodeList.Add(barCode);
                }
                rb.positions.Clear();
                rb.ResultList.Clear();
                for (int i = 0; i < rb.cellNum; i++)
                {
                    string position = (byt[20 + 2 * i] * 256 + byt[20 + 2 * i + 1]).ToString().Trim('\r').Trim('\n');
                    rb.positions.Add(position);
                    rb.ResultList.Add(position);
                }
                //业务逻辑处理
                ShowEquipmentTaskInfo(rb);
            }
        }

        private void BindPickRoboInfo(string robotnum, byte[] byt)
        {
            RobotInfo rb = RobotsInfo.Find(
                 delegate (RobotInfo ss)
                 {
                     return ss.robotnum == robotnum;
                 }
             );
            if (rb != null)
            {
                rb.wcstaskno = (byt[0] * 256 + byt[1]).ToString();//机械手状态 0， 未启动；1，自动；2，手动；3，故障
                rb.rbtaskno = byt[2] * 256 + byt[3]; //机器人任务号 0，无任务；1，拆盘中
                rb.rbstate = byt[4] * 256 + byt[5];
                rb.rbpickcount = byt[6] * 256 + byt[7];//拆完数量
                rb.trayreading = byt[8] * 256 + byt[9];//拆盘交互申请 （1拆盘申请 2WCS收到回复 3 拆盘完成 ）
                rb.heart = byt[10] * 256 + byt[11];
                rb.alarmCode = byt[12] * 256 + byt[13];//故障代码
                robotStatus[rb.name] = rb.rbstate.ToString();
                rb.BarCodeList.Clear();
                rb.ResultList.Clear();
                for (int i = 0; i < rb.cellNum; i++)
                {
                    byte[] ResultTmp = new byte[2];
                    string result = string.Empty;
                    result = (byt[20 + (2 * i)] * 256 + byt[20 + (2 * i + 1)]).ToString().Trim('\r').Trim('\n'); ;
                    rb.ResultList.Add(result);

                    byte[] BatteryCodeTmp = new byte[30];
                    string barCode = string.Empty;
                    Array.Copy(byt, 68 + 30 * i, BatteryCodeTmp, 0, 30);
                    barCode = Encoding.ASCII.GetString(BatteryCodeTmp).Replace(" ", "").Trim('\0').Trim('\r').Trim('\n');
                    rb.BarCodeList.Add(barCode);
                }
                //业务逻辑处理
                ShowEquipmentTaskInfo(rb);
            }
        }

        /// <summary>
        /// 重新连接
        /// </summary>
        /// <param name="strIP"></param>
        /// <param name="retryCount"></param>
        private void ReConnect(string strIP, int retryCount = 1)
        {
            if (RobotReConnectPLC != null)
            {
                if (PLCList.ContainsKey(strIP))
                {
                    bool flag = true;
                    int i_Count = 1;
                    while (flag)
                    {
                        if (i_Count > retryCount)
                        {
                            break;
                        };
                        PLCList[strIP].ConnectClose();
                        ShowMsg("Break", string.Format("PLC：{0}，尝试连接次数：{1}", strIP, i_Count));
                        OperateResult connect = PLCList[strIP].ConnectServer();
                        if (connect.IsSuccess)
                        {
                            ShowMsg("Break", string.Format("PLC：{0}，连接成功", strIP, i_Count));
                            flag = false;
                            break;
                        }
                        else
                        {
                            i_Count++;
                        }
                    }
                }
            }
        }

        public bool WriteRobotInfo(string robottype, string rbnum, RobotCommand cmd, string[] str, int index, int length,int cellNum)
        {
            if (robottype == "PutRobot")
            {
                switch (cmd)
                {
                    case RobotCommand.InplaceResult:
                        int inplace = 8;
                        return Write(rbnum, "2", inplace, 2);//到位申请                       
                    case RobotCommand.CheckResult:
                        byte[] byt = new byte[(str.Length - 1) * 2];
                        for (int i = 1; i < str.Length; i++)
                        {
                            byte[] bytemp = ConvertHelper.GetHexBytes(str[i]);
                            Array.Copy(bytemp, 0, byt, (i - 1) * 2, 2);
                        }
                        if (cellNum == 2)
                        {
                            byte[] bytemp = new byte[byt.Length];
                            Array.Copy(byt, index == 12 ? 0 : 4, bytemp, 0, 4);
                            if (!WriteBytes(rbnum, bytemp, index, 4))
                            {
                                return false;
                            }
                            //if (index == 12)
                            //{
                            //    Write(rbnum, str[1], 12, 2);//写入1号电池校验结果
                            //    Write(rbnum, str[2], 14, 2);//写入2号电池校验结果
                            //}
                            //else if (index == 16)
                            //{
                            //    Write(rbnum, str[3], 16, 2);//写入3号电池校验结果
                            //    Write(rbnum, str[4], 18, 2);//写入4号电池校验结果
                            //}
                        }
                        else
                        {
                            //Write(rbnum, str[1], 12, 2);//写入1号电池校验结果
                            //Write(rbnum, str[2], 14, 2);//写入2号电池校验结果
                            //Write(rbnum, str[3], 16, 2);//写入3号电池校验结果
                            //Write(rbnum, str[4], 18, 2);//写入4号电池校验结果
                            if (!WriteBytes(rbnum, byt, index, cellNum * 2))
                            {
                                return false;
                            }
                        }
                        return Write(rbnum, str[0], 8, 2);//写入电池校验结果str[0]
                    case RobotCommand.BindResult:
                        return Write(rbnum, str[0], index, length);//抓取完成申请
                    case RobotCommand.completePut:
                        return Write(rbnum, str[0], 8, 2);//整盘完成申请
                }

            }
            else if (robottype == "PickRobot")
            {
                switch (cmd)
                {
                    case RobotCommand.PickCommand:
                        byte[] byt = new byte[cellNum * 2];
                        byte[] byt2 = new byte[30 * cellNum];
                        byte[] BatteryCodeTmp = new byte[30];

                        for (int i = 0; i < str.Length; i++)
                        {
                            if (i < cellNum)
                            {
                                byte[] bytemp = ConvertHelper.GetHexBytes(str[i]);
                                Array.Copy(bytemp, 0, byt, i * 2, 2);
                            }
                            else
                            {
                                BatteryCodeTmp = System.Text.ASCIIEncoding.ASCII.GetBytes(str[i].PadRight(30, '\0'));
                                Array.Copy(BatteryCodeTmp, 0, byt2, 30 * (i - cellNum), 30);
                            }
                        }
                        if (WriteBytes(rbnum, byt, 20, cellNum * 2))//写入电芯状态
                        {
                            if (WriteBytes(rbnum, byt2, 68, cellNum * 30))
                            {
                                if (Write(rbnum, "2", 8, 2))//回复申请
                                    return true;
                                else
                                    return false;
                            }
                        }
                        break;
                    //写入电芯状态
                    case RobotCommand.ReWorkResponse:
                        if (Write(rbnum, "2", 8, 2))//回复装盘数量
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case RobotCommand.enableReworkPut:
                        if (WriteBit(rbnum, "2", 14, 1))//允许本地组复测盘
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case RobotCommand.completePick:
                        if (Write(rbnum, "4", 8, 2))//拆盘完成回复信息
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case RobotCommand.SendReworkBarcode://发送复测工位上的托盘条码给机械手

                        byte[] byt1 = new byte[2];
                        Array.Copy(ConvertHelper.GetHexBytes(str[0]), 0, byt1, 0, 2);
                        if (WriteBytes(rbnum, byt1, 16, 2))//写入电芯状态
                        {
                            if (WriteBit(rbnum, "2", 19, 1))//回复申请
                                return true;
                            else
                                return false;
                        }
                        else
                        {
                            return false;
                        }

                        break;
                    case RobotCommand.completePut:
                        return WriteBit(rbnum, "7", 19, 1);//抓取完成申请
                        break;
                    case RobotCommand.PickCommand_hc:
                        if (WriteBit(rbnum, "2", 4, 1))//抓取完成申请
                            return WriteBit(rbnum, str[0], 5, 1);
                        break;
                }
            }
            return false;
        }
        public bool ReadRobotInfo(RobotInfo rb,int index, int length, ref Byte[] rbBuffer)
        {
            if (ReadPlc(PLCList[rb.key_ip], rb.DBAddress, index, length, ref rbBuffer))
            {

                return true;
            }
                return false;
        }
        private bool Write(string rbnum, string value, int index, int length = 0)
        {
            RobotInfo rb = RobotsInfo.Find(
                 delegate(RobotInfo item)
                 {
                     return item.robotnum == rbnum;
                 }
             );
            if (rb != null)
            {
                byte[] byt;
                if (length == 0)
                    byt = new byte[1];
                else
                    byt = new byte[length];
                Array.Copy(ConvertHelper.GetHexBytes(value), 0, byt, 0, 2);
                if (true)//调试模式
                {
                    //if (PLCList[rb.key_ip].Write(rb.DBAddress, index, length, byt))
                    if (WritePlc(PLCList[rb.key_ip], rb.DBAddress, rb.start + index, byt))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        private bool WriteBit(string rbnum, string value, int index = 0, int length = 1)
        {

            RobotInfo rb = RobotsInfo.Find(
                 delegate (RobotInfo item)
                 {
                     return item.robotnum == rbnum;
                 }
             );
            if (rb != null)
            {
                byte[] byt = new byte[length];
                byte byttem = Convert.ToByte(value);
                byte[] bytArray = new byte[2];
                bytArray[0] = byttem;
                Array.Copy(bytArray, 0, byt, 0, 1);

                // if (PLCList[rb.key_ip].Write(rb.DBAddress, rb.start + index, length, byt))
                if (WritePlc(PLCList[rb.key_ip], rb.DBAddress, rb.start + index, byt))
                    return true;
                else
                    return false;
            }
            return false;
        }
        private bool WriteBytes(string rbnum, byte[] btys, int index = 0, int length = 1)
        {

            RobotInfo rb = RobotsInfo.Find(
                 delegate (RobotInfo item)
                 {
                     return item.robotnum == rbnum;
                 }
             );
            if (rb != null)
            {
                // if (PLCList[rb.key_ip].Write(rb.DBAddress, rb.start + index, length, btys))
                if (WritePlc(PLCList[rb.key_ip], rb.DBAddress, rb.start + index, btys))
                    return true;
                else
                    return false;
            }
            return false;
        }

        public string getRobotStatus(string name)
        {
            if (robotStatus.ContainsKey(name))
                return robotStatus[name];
            else
                return "3";
        }
    }
}
